﻿using System.Collections;
using System.Data;
using System.Reflection;
using Consul;
using Infrastructure.Attribute;
using Infrastructure.Centers;
using Infrastructure.FileCenter;
using Infrastructure.FileCenter.Dtos;
using Infrastructure.GlobalException;
using Infrastructure.Helper;
using Infrastructure.Model.ApiResult;
using Infrastructure.Model.SideCar;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Minio;
using Newtonsoft.Json;
using Oracle.ManagedDataAccess.Client;
using SqlSugar.IOC;

namespace Infrastructure.Extensions
{
    /// <summary>
    /// 服务注册扩展：提供服务中心相关的依赖注入配置
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 注册核心基础设施服务
        /// </summary>
        public static IServiceCollection AddCoreServices(this IServiceCollection services, IConfiguration configuration)
        {
            // 跨域配置
            services.AddCors(options => options.AddPolicy("AllowSpecificOrigins", policy =>
                policy.AllowAnyMethod()
                    .SetIsOriginAllowed(_ => true)
                    .AllowAnyHeader()
                    .AllowCredentials()
                    .WithExposedHeaders("trace_id")));

            // MVC配置
            services.AddControllers()
                .AddNewtonsoftJson()
                .AddMvcLocalization();

            // Swagger文档
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "WebApi",
                    Version = "v1.0",
                    Description = "API文档"
                });

                // 启用XML注释（如果有）
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                if (File.Exists(xmlPath))
                    c.IncludeXmlComments(xmlPath);
            });

            // 分布式缓存
            //services.AddDistributedRedisCache(o =>
            //{
            //    o.Configuration = configuration["RedisUrl"];
            //    o.InstanceName = $"{configuration["RedisPrefix"]}:";
            //});

            // HTTP上下文访问
            services.AddHttpContextAccessor();
            return services;
        }


        public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration)
        {
            // 缓存配置
            services.AddDistributedMemoryCache(); // 或使用Redis

            // 会话配置
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromMinutes(20);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });

            services.AddDataProtection();
        /*    services.AddScoped<VerifyAttribute>(); */// ✅ 先注册服务
            //services.AddControllers(options =>
            //{
            //    // 改为以过滤器形式注册，而不是全局添加
            //    options.Filters.AddService<VerifyAttribute>();// ✅ 从 DI 解析
            //});
            /*options.Filters.Add<VerifyAttribute>()：直接实例化过滤器，不会走 DI 容器，导致依赖注入失效。
              options.Filters.AddService<VerifyAttribute>()：从 DI 容器解析过滤器，支持依赖注入。AddService 底层原理
              AddService 会告诉 ASP.NET Core：不要直接 new 这个过滤器，而是从 DI 容器获取它！
            相当于：options.Filters.Add(new TypeFilterAttribute(typeof(VerifyAttribute)));TypeFilterAttribute 会负责从 DI 解析 VerifyAttribute。*/
            return services;
        }



        /// <summary>
        /// 注册数据访问层服务
        /// </summary>
        public static IServiceCollection AddDataAccess(this IServiceCollection services, IConfiguration configuration)
        {
            // SugarORM配置（移除了Console输出）
            SugarIocServices.AddSqlSugar(new IocConfig
            {
                ConnectionString = configuration["Database:Connection"],
                DbType = IocDbType.Oracle,
                IsAutoCloseConnection = true
            });

            // Dapper配置（保持不变）
            services.AddTransient<IDbConnection>(_ =>
                new OracleConnection(configuration["Database:Connection"]));

            return services;
        }

        /// <summary>
        /// 注册应用层服务
        /// </summary>
        public static IServiceCollection AddApplicationServices(this IServiceCollection services)
        {
            // 自动注册服务
            services.AddAppService(["Infrastructure", "Service", "Repository"]);

            // 对象映射
            services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

            return services;
        }
        /// <summary>
        /// 注册操作日志过滤器
        /// </summary>
        public static IServiceCollection AddOperationLogFilter(this IServiceCollection services)
        {
            // 1. 注册日志服务依赖
            services.TryAddScoped<ISysOperLogService, SysOperLogService>();

            // 2. 注册日志过滤器
            services.AddScoped<LogActionFilter>();

            // 3. 配置全局过滤器
            services.Configure<MvcOptions>(options =>
            {
                options.Filters.AddService<LogActionFilter>();
            });

            return services;
        }
        /// <summary>
        /// 注册服务中心相关服务到DI容器
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="setupAction">服务中心配置委托</param>
        /// <exception cref="ArgumentNullException">配置委托为空时抛出</exception>
        /// <exception cref="Exception">Consul地址获取失败时抛出</exception>
        public static void AddServiceCenter(this IServiceCollection services, Action<ServiceCenterOption> setupAction)
        {
            // 参数校验
            if (setupAction == null)
                throw new ArgumentNullException(nameof(setupAction));

            // 初始化配置对象
            var options = new ServiceCenterOption();
            setupAction(options); // 执行外部配置委托

            // 动态获取Consul地址（当配置中未提供时）
            if (string.IsNullOrWhiteSpace(options.ConsulUrl))
            {
                // 构造请求URL（注意：需确保ServiceCenterUrl和GetConsulUrl有效）
                var requestUrl = $"{options.ServiceCenterUrl}/{options.GetConsulUrl}";

                // 发送API请求获取Consul地址
                var result = new RestfulHelper().Post(requestUrl, new Hashtable
            {
                { "ServiceName", options.ServiceName }
            });

                // 处理API响应
                if (!result.IsSuccess)
                    throw new Exception($"服务中心配置失败: {result.Msg}");

                // 处理返回数据（移除JSON字符串的引号）
                options.ConsulUrl = result.Data.ToString().Replace("\"", "");
            }

            // 注册Consul客户端（瞬时生命周期）
            services.AddTransient<IConsulClient>(provider =>
                new ConsulClient(config =>
                {
                    // 配置Consul服务器地址
                    config.Address = new Uri(options.ConsulUrl);
                }));

            // 注册服务中心客户端（单例生命周期）
            services.AddSingleton<IServiceCenter>(provider =>
                new ServiceCenter(
                    provider.GetRequiredService<IConsulClient>(),
                    options
                ));
        }

        /// <summary>
        /// 将文件中心服务注册到依赖注入容器的扩展方法
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="setupAction">文件中心配置委托</param>
        /// <exception cref="ArgumentNullException">当setupAction为null时抛出</exception>
        /// <exception cref="Exception">当文件中心服务不可用或配置失败时抛出</exception>
        public static void AddFileCenter(this IServiceCollection services, Action<FileCenterOption> setupAction)
        {
            if (setupAction == null) throw new ArgumentNullException("setupAction");

            FileCenterOption optFileCenter = new FileCenterOption();
            setupAction(optFileCenter);
            string text = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/" + optFileCenter.GetMinioUrl, JsonConvert.SerializeObject(new DtoMinioInfoReq
            {
                AppId = optFileCenter.AppId,
                AccessKey = optFileCenter.AccessKey
            }));
            if (!string.IsNullOrWhiteSpace(text))
            {
                ApiResult apiResult = JsonConvert.DeserializeObject<ApiResult>(text);
                if (!apiResult.IsSuccess)
                {
                    throw new Exception("Failed to query file center, please check file center :  " + text);
                }
                DtoMinioInfoRes dtoMinioInfoRes = JsonConvert.DeserializeObject<DtoMinioInfoRes>(apiResult.Data.ToString());
                optFileCenter.MinioUrl = dtoMinioInfoRes.MinioUrl;
                optFileCenter.Username = dtoMinioInfoRes.MinioUsername;
                optFileCenter.Password = dtoMinioInfoRes.MinioPassword;
                services.Configure(delegate (KestrelServerOptions options)
                {
                    options.Limits.MaxRequestBodySize = optFileCenter.MaxSizeMBPerFile * 1024 * 1024;
                });
                services.Configure(delegate (FormOptions x)
                {
                    x.MultipartBodyLengthLimit = optFileCenter.MaxSizeMBPerFile * 1024 * 1024;
                });
                services.AddTransient((IServiceProvider options) => new MinioClient().WithEndpoint(optFileCenter.MinioUrl).WithCredentials(optFileCenter.Username, optFileCenter.Password).Build());
                services.AddSingleton((Func<IServiceProvider, IFileCenter>)((IServiceProvider sp) => new _FileCenter(sp.GetRequiredService<MinioClient>(), optFileCenter, sp.GetRequiredService<IHttpContextAccessor>())));
                return;
            }

            throw new Exception("Failed to query file center, please check file center :  result is null");
        }

        /// <summary>
        /// IServiceCollection 的扩展方法，用于注册和配置 Sidecar 选项
        /// 使应用程序可以使用 IOptions<SideCarOption> 模式访问配置
        /// </summary>
        /// <param name="services">依赖注入容器服务集合</param>
        /// <param name="setupAction">配置选项的回调方法，用于设置 SideCarOption 属性</param>
        /// <exception cref="ArgumentNullException">当 setupAction 为 null 时抛出</exception>
        /// <example>
        /// 使用示例：
        /// services.AddSideCar(options => {
        ///     options.BaseUrl = "http://localhost:5000";
        ///     options.IsActivated = true;
        /// });
        /// </example>
        public static void AddSideCar(this IServiceCollection services, Action<SideCarOption> setupAction)
        {
            // 参数有效性验证，确保配置方法有效
            if (setupAction == null)
            {
                throw new ArgumentNullException(nameof(setupAction),
                    "必须提供配置方法，用于初始化 Sidecar 选项参数");
            }

            // 使用 ASP.NET Core 的标准配置模式注册选项
            // 这会注册 IOptions<SideCarOption>, IOptionsSnapshot<SideCarOption> 等服务
            services.Configure(setupAction);
        }

      
    }
}